home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / RCS / ip.c,v < prev    next >
Encoding:
Text File  |  1990-07-09  |  62.0 KB  |  2,425 lines

  1. head     1.9;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.9
  10. date     89.10.22.12.15.17;  author nelson;  state Exp;
  11. branches ;
  12. next     1.8;
  13.  
  14. 1.8
  15. date     89.03.23.09.54.37;  author brent;  state Exp;
  16. branches ;
  17. next     1.7;
  18.  
  19. 1.7
  20. date     89.02.21.10.13.07;  author brent;  state Exp;
  21. branches ;
  22. next     1.6;
  23.  
  24. 1.6
  25. date     88.09.15.09.33.18;  author mendel;  state Exp;
  26. branches ;
  27. next     1.5;
  28.  
  29. 1.5
  30. date     88.08.26.16.34.36;  author mendel;  state Exp;
  31. branches ;
  32. next     1.4;
  33.  
  34. 1.4
  35. date     88.08.25.13.48.53;  author mendel;  state Exp;
  36. branches ;
  37. next     1.3;
  38.  
  39. 1.3
  40. date     88.08.16.11.17.08;  author mendel;  state Exp;
  41. branches ;
  42. next     1.2;
  43.  
  44. 1.2
  45. date     88.04.27.09.08.43;  author brent;  state Exp;
  46. branches ;
  47. next     1.1;
  48.  
  49. 1.1
  50. date     88.04.27.08.51.37;  author brent;  state Exp;
  51. branches ;
  52. next     ;
  53.  
  54.  
  55. desc
  56. @IP Protocol
  57. @
  58.  
  59.  
  60. 1.9
  61. log
  62. @Fix to packet header handling so the proper byte swapping is done.
  63. @
  64. text
  65. @/* 
  66.  * ip.c --
  67.  *
  68.  *      Routines to handle the IP protocol. IP packets that are received
  69.  *      from the network layer are validated and passed to the next
  70.  *      protocol layer. If the packet is fragmented, it is reassembled
  71.  *      before passed to the next layer. This file also contains
  72.  *      routines to format IP header in a packet and to send the packet to
  73.  *      the network for output. The packet may be sent in fragments if it
  74.  *      is too large for the network.
  75.  *
  76.  *    The IP protocol specification used by the routines in this file
  77.  *    is RFC 791 "Internet Protocol", Sept. 1981.
  78.  *
  79.  *
  80.  *    Based on 4.3 BSD code:
  81.  *    "@@(#)ip_input.c  7.9 (Berkeley) 3/15/88"
  82.  *    "@@(#)ip_output.c 7.9 (Berkeley) 3/15/88"
  83.  *
  84.  * Copyright 1987 Regents of the University of California
  85.  * All rights reserved.
  86.  * Permission to use, copy, modify, and distribute this
  87.  * software and its documentation for any purpose and without
  88.  * fee is hereby granted, provided that the above copyright
  89.  * notice appear in all copies.  The University of California
  90.  * makes no representations about the suitability of this
  91.  * software for any purpose.  It is provided "as is" without
  92.  * express or implied warranty.
  93.  */
  94.  
  95. #ifndef lint
  96. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/ip.c,v 1.8 89/03/23 09:54:37 brent Exp Locker: nelson $ SPRITE (Berkeley)";
  97. #endif not lint
  98.  
  99.  
  100. #include "sprite.h"
  101. #include "ipServer.h"
  102. #include "stat.h"
  103. #include "ip.h"
  104. #include "icmp.h"
  105. #include "route.h"
  106. #include "raw.h"
  107.  
  108. #include "list.h"
  109. #include "spriteTime.h"
  110. #include "fs.h"
  111.  
  112. /*
  113.  * Information needed to aid in reassembly of a datagram from its fragments. 
  114.  *
  115.  * The fragInfoList is a list of DgramFragInfo elements with one element
  116.  * per fragmented datagram. The fragments are kept on the dataList linked
  117.  * list within each DgramFragInfo element.  All fragments of a datagram
  118.  * have the same source, destination, protocol and identification fields
  119.  * in their IP headers.  If the datagram isn't reassembled before the
  120.  * timeToLive field goes to 0, all fragments are freed and the DgramFragInfo
  121.  * element is removed from the fragInfoList.
  122.  */
  123.  
  124. typedef struct {
  125.     List_Links        links;        /* Links to next and prev. items. */
  126.  
  127.     /*
  128.      * The following 4 fields in the IP header uniquely identify the datagram. 
  129.      * A fragment belongs to this datagram if all 4 fields match.
  130.      */
  131.     Net_InetAddress    source;        /* Sender of packet. */
  132.     Net_InetAddress    dest;        /* Destination of packet. */
  133.     unsigned char    protocol;    /* Protocol. */
  134.     unsigned short    ident;        /* Datagram ID. */
  135.  
  136.     int            numFrags;    /* Number of fragments. */
  137.     int            timeToLive;    /* # of seconds before the fragments 
  138.                      * are dropped. */
  139.     List_Links        dataList;    /* List head of data info elements for 
  140.                      * fragments that have arrived. */
  141. } DgramFragInfo;
  142.  
  143. /*
  144.  * List head of the list of DgramFragInfo elements.
  145.  */
  146. static List_Links    fragInfoList;
  147.  
  148.  
  149. /*
  150.  * Information about a particular fragment within a datagram.
  151.  *
  152.  * Each fragment of a datagram has one of these structures in the 
  153.  * dataList list of the DgramFragInfo element.
  154.  */
  155. typedef struct {
  156.     List_Links        links;        /* Links to next and prev. items. */
  157.     unsigned short    fragOffset;    /* Offset from the beginning of 
  158.                      * the datagram for the data in
  159.                      * this frgament. */
  160.     int            dataOffset;    /* Offset from beginning of this 
  161.                      * fragment data where usable data 
  162.                      * starts. */
  163.     int            dataLen;    /* Size in bytes of usable data. */
  164.     IPS_Packet        fragPacket;    /* Address of fragment packet. */
  165. } FragDataInfo;
  166.  
  167. /*
  168.  * Amount of time between calls to FragTimeoutHandler.
  169.  */
  170. static Time    fragTimeout = { 1, 0 };
  171.  
  172.  
  173. /*
  174.  * The protocolCallback array of functions is used to pass an IP packet
  175.  * to the next protocol layer. A higher-level protocol establishes a 
  176.  * callback using IP_SetProtocolHandler. The maximum number of callbacks is 
  177.  * 255 since the protocol field in the IP header 8 bits wide.
  178.  */
  179.  
  180. #define MAX_PROTOCOL_NUM    255
  181. static void (*protocolCallback[MAX_PROTOCOL_NUM+1])();
  182.  
  183. /*
  184.  * Forward declarations.
  185.  */
  186. static Boolean        ReassemblePacket();
  187. static ReturnStatus    ProcessOptions();
  188. static void        ForwardPacket();
  189. static DgramFragInfo    *FreeFragments();
  190. static void        SaveRoute();
  191. static void        FragTimeoutHandler();
  192. static int         CopyHeader();
  193. static Boolean        CanForward();
  194.  
  195. #ifdef DEBUG
  196. static void         TestInputProc();
  197. #endif
  198.  
  199. /*
  200.  * Macro to swap the fragOffset field.
  201.  */
  202. #define SWAP_FRAG_OFFSET_HOST_TO_NET(ptr) { \
  203.     short    *shortPtr; \
  204.     shortPtr = ((short *)&ptr->ident) + 1; \
  205.     *shortPtr = Net_HostToNetShort(*shortPtr); \
  206.  
  207. #define SWAP_FRAG_OFFSET_NET_TO_HOST(ptr) { \
  208.     short    *shortPtr; \
  209.     shortPtr = ((short *)&ptr->ident) + 1; \
  210.     *shortPtr = Net_NetToHostShort(*shortPtr); \
  211.  
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * IP_MemBin --
  217.  *
  218.  *    Optimize memory allocation of data structures that are dynamically
  219.  *    allocated by IP.
  220.  *
  221.  * Results:
  222.  *    None.
  223.  *
  224.  * Side effects:
  225.  *    Calls Mem_Bin.
  226.  *
  227.  *----------------------------------------------------------------------
  228.  */
  229.  
  230. void
  231. IP_MemBin()
  232. {
  233.     Mem_Bin(sizeof(DgramFragInfo));
  234.     Mem_Bin(sizeof(FragDataInfo));
  235.     Mem_Bin(sizeof(Net_IPHeader));
  236.     Mem_Bin(NET_ETHER_MAX_BYTES);
  237. }
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * IP_Init --
  243.  *
  244.  *    Initializes the DgramFragInfo list. This routine must be
  245.  *    called before any packets are processed. Arranges to have 
  246.  *    FragTimeoutHandler to be called at regular intervals.
  247.  *
  248.  * Results:
  249.  *    None.
  250.  *
  251.  * Side effects:
  252.  *    The DgramFragInfo list is initialized. A timeout handler is
  253.  *    created.
  254.  *
  255.  *----------------------------------------------------------------------
  256.  */
  257.  
  258. void
  259. IP_Init()
  260. {
  261.     List_Init(&fragInfoList);
  262.  
  263.     (void) Fs_TimeoutHandlerCreate(fragTimeout, TRUE, FragTimeoutHandler, 
  264.         (ClientData) 0);
  265. }
  266.  
  267.  
  268. /*
  269.  *----------------------------------------------------------------------
  270.  *
  271.  * IP_SetProtocolHandler --
  272.  *
  273.  *    Each IP packet has a protocol field that specifies the next protocol
  274.  *    layer to be called once the IP input routine has finished with
  275.  *    the datagram.  This routine establishes the procedure that will be
  276.  *    called for the given protocol.
  277.  *
  278.  *    The proc parameter should be declared as follows:
  279.  *
  280.  *    void
  281.  *    Proc(netID, packetPtr)
  282.  *        Rte_NetID    netID;
  283.  *        IPS_Packet    *packetPtr;
  284.  *    {
  285.  *    }
  286.  *
  287.  *    It is responsible for freeing the packet once it is done with it.
  288.  *
  289.  * Results:
  290.  *    None.
  291.  *
  292.  * Side effects:
  293.  *    The table of protocol callbacks is updated.
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297.  
  298. void
  299. IP_SetProtocolHandler(protocol, proc)
  300.     int        protocol;    /* Assigned protocol number from RFC 1010. */
  301.     void    (*proc)();    /* Procedure to call to handle packets with
  302.                  * the protocol #. */
  303. {
  304.     if (protocol < 0 || protocol > MAX_PROTOCOL_NUM) {
  305.     (void) fprintf(stderr, "Warning: IP_SetProtocolHandler: bad protocol # (%d)\n",
  306.             protocol);
  307.     return;
  308.     }
  309.     if (proc == NULL) {
  310.     (void) fprintf(stderr, 
  311.         "Warning: IP_SetProtocolHandler: NULL procedure address\n");
  312.     }
  313.     protocolCallback[protocol] = proc;
  314. }
  315.  
  316.  
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * IP_AcceptedProtocol --
  321.  *
  322.  *    Determine if a IP protocol has a handler established for it.  This
  323.  *    is used at open time in order to deny opening an IP protocol that
  324.  *    is not implemented.
  325.  *
  326.  * Results:
  327.  *    TRUE if a callback has been installed for the protocol.
  328.  *
  329.  * Side effects:
  330.  *    None.
  331.  *
  332.  *----------------------------------------------------------------------
  333.  */
  334.  
  335. Boolean
  336. IP_AcceptedProtocol(protocol)
  337.     int        protocol;    /* Assigned protocol number from RFC 1010. */
  338. {
  339.     if (protocol < 0 || protocol > MAX_PROTOCOL_NUM) {
  340.     return(FALSE);
  341.     } else if (protocolCallback[protocol] != NULL) {
  342.     return(TRUE);
  343.     } else {
  344.     return(FALSE);
  345.     }
  346. }
  347.  
  348. /*
  349.  *----------------------------------------------------------------------
  350.  *
  351.  * IP_Input --
  352.  *
  353.  *    The main routine to deal with new IP packets from the network.
  354.  *    The packet is checked to make sure that it has the proper sizes
  355.  *    and that it has not been corrupted. The packet's destination is 
  356.  *    checked to see if it is for us or whether it needs to be forwarded
  357.  *    to the appropriate gateway. IP options processing and fragment 
  358.  *    reassembly is also initiated here.  Once processed, the packet 
  359.  *    may be handed to the next protocol layer.
  360.  *
  361.  *    Terminology: a packet is the data received from the network.
  362.  *    It may a complete IP datagram or a fragment of a datagram.
  363.  *
  364.  * Results:
  365.  *    SUCCESS    - The packet was processed successfully or was a fragment. 
  366.  *          The caller can NOT deallocate the packet memory.
  367.  *    FAILURE    - The packet was malformed or was not used. The caller 
  368.  *          must deallocate the packet memory.
  369.  *
  370.  * Side effects:
  371.  *    The fragment queue may be changed. Various statistics counters 
  372.  *    are incremented.
  373.  *
  374.  *
  375.  *    The following fields are converted from network order to host order.
  376.  *     - totalLen
  377.  *     - ident
  378.  *     - offset + flags
  379.  *     - checksum
  380.  *     - source
  381.  *     - dest
  382.  *    They must be changed back if the packet needs to be output 
  383.  *    to the network.
  384.  *
  385.  *
  386.  *----------------------------------------------------------------------
  387.  */
  388.  
  389. ReturnStatus
  390. IP_Input(netID, packetPtr)
  391.     Rte_NetID    netID;        /* ID of network interface that this packet
  392.                  * arrived on. */
  393.     IPS_Packet    *packetPtr;    /* Packet layout descriptor. */
  394. {
  395.     register Net_IPHeader    *ipHeaderPtr;
  396.     register int        headerLenInBytes;
  397.  
  398.  
  399.     stats.ip.totalRcv++;
  400.  
  401.     if (packetPtr->ipLen < sizeof(Net_IPHeader)) {
  402.     stats.ip.shortPacket++;
  403.     if (ips_Debug) {
  404.         fprintf(stderr, "IP_Input: Short packet, len=%d\n", 
  405.                 packetPtr->ipLen);
  406.     }
  407.     return(FAILURE);
  408.     }
  409.  
  410.     ipHeaderPtr =  packetPtr->ipPtr;
  411.     headerLenInBytes = ipHeaderPtr->headerLen * 4;
  412.  
  413.     if (headerLenInBytes < sizeof(Net_IPHeader)) {
  414.     stats.ip.shortHeader++;
  415.     if (ips_Debug) {
  416.         fprintf(stderr, "IP_Input: Short header, len=%d\n", 
  417.                 headerLenInBytes);
  418.     }
  419.     return(FAILURE);
  420.     }
  421.  
  422.     /*
  423.      * See if the header checksum is ok. RFC791 says the header checksum 
  424.      * is computed as if ipHeaderPtr->checksum is 0 but we recompute it with
  425.      * whatever value that's there. If the packet is good, then the sum not
  426.      * including ipHeaderPtr->checksum should be the 1's complement of 
  427.      * ipHeaderPtr->checksum and when added together (during the checksum 
  428.      * computation), they should equal 0.
  429.      */
  430.     if (Net_InetChecksum(headerLenInBytes, (Address) ipHeaderPtr) != 0) {
  431.     stats.ip.badChecksum++;
  432.     if (ips_Debug) {
  433.         fprintf(stderr, "IP_Input: Bad check sum\n");
  434.     }
  435.     return(FAILURE);
  436.     }
  437.  
  438.     ipHeaderPtr->totalLen = Net_NetToHostShort(ipHeaderPtr->totalLen);
  439.     ipHeaderPtr->ident    = Net_NetToHostShort(ipHeaderPtr->ident);
  440.     SWAP_FRAG_OFFSET_NET_TO_HOST(ipHeaderPtr);
  441.  
  442.     /*
  443.      * Change the length in the packet descriptor to the true length.
  444.      * The previous value for the length was calculated from the
  445.      * packet size from the network and that might have been too large.
  446.      */
  447.     packetPtr->ipLen = ipHeaderPtr->totalLen;
  448.  
  449.     if (ipHeaderPtr->totalLen < ipHeaderPtr->headerLen) {
  450.     stats.ip.shortLen++;
  451.     if (ips_Debug) {
  452.         fprintf(stderr, "IP_Input: Short length, len=%d\n", 
  453.                 ipHeaderPtr->totalLen);
  454.     }
  455.     return(FAILURE);
  456.     }
  457.  
  458.     if (headerLenInBytes > sizeof(Net_IPHeader)) {
  459.     /*
  460.      * Process the options that follow the basic IP header.
  461.      */
  462.     if (!ProcessOptions(headerLenInBytes, ipHeaderPtr)) {
  463.         if (ips_Debug) {
  464.         fprintf(stderr, "IP_Input: Bad options\n");
  465.         }
  466.         return(FAILURE);
  467.     }
  468.     }
  469.  
  470.     if (ips_Debug) {
  471.     (void) fprintf(stderr, 
  472.             "IP Input: %d bytes, prot %d <%x> <-- <%x,#%d> flags %x\n",
  473.             packetPtr->ipLen,
  474.             ipHeaderPtr->protocol,
  475.             Net_NetToHostInt(ipHeaderPtr->dest), 
  476.             Net_NetToHostInt(ipHeaderPtr->source),
  477.             ipHeaderPtr->ident,
  478.             ipHeaderPtr->flags);
  479.  
  480.     }
  481.  
  482.  
  483.     /*
  484.      * See if the packet is for us. If it isn't then forward it to
  485.      * the appropriate host.
  486.      */
  487.     
  488.     if (!Rte_AddrIsForUs(ipHeaderPtr->dest)) {
  489.     stats.ip.forwards++;
  490.     if (ips_Debug) {
  491.         fprintf(stderr, "IP_Input: Forwarding packet\n");
  492.     }
  493.     ForwardPacket(packetPtr);
  494.     return(FAILURE);
  495.     }
  496.  
  497.  
  498.     /*
  499.      * Fragmentation test: 
  500.      * See if this packet is a complete datagram or a fragment of one.
  501.      * If it's a fragment, then search the queue and try to reassemble the
  502.      * complete datagram.  If it's a complete datagram already, then 
  503.      * don't search the queue; even though there may be fragments for the
  504.      * datagram on the queue, let the timeout routine remove them.
  505.      */
  506.     if ((ipHeaderPtr->flags & NET_IP_MORE_FRAGS) ||
  507.     (ipHeaderPtr->fragOffset != 0)) {
  508.  
  509.     register DgramFragInfo    *fragInfoPtr;
  510.     Boolean    foundFrags;
  511.  
  512.     stats.ip.fragsRcv++;
  513.     if (ips_Debug) {
  514.         fprintf(stderr, "IP_Input: Received fragment, offset=%d\n",
  515.             ipHeaderPtr->fragOffset);
  516.     }
  517.  
  518.     foundFrags = FALSE;
  519.     LIST_FORALL(&fragInfoList, (List_Links *) fragInfoPtr) {
  520.         if ((ipHeaderPtr->ident == fragInfoPtr->ident) &&
  521.         (ipHeaderPtr->protocol == fragInfoPtr->protocol) &&
  522.         (ipHeaderPtr->source == fragInfoPtr->source) &&
  523.         (ipHeaderPtr->dest == fragInfoPtr->dest)) {
  524.         foundFrags = TRUE;
  525.         break;
  526.         }
  527.     }
  528.     if (!foundFrags) {
  529.         /*
  530.          * First fragment to arrive so there's no information yet.
  531.          * ReassemblePacket will create a list for this datagram.
  532.          */
  533.         if (ips_Debug) {
  534.         fprintf(stderr, "IP_Input: First fragment\n");
  535.         }
  536.         fragInfoPtr = (DgramFragInfo *) NULL;
  537.     }
  538.  
  539.     if (!ReassemblePacket(fragInfoPtr, packetPtr)) {
  540.         /*
  541.          * The fragment did not complete the packet.
  542.          */
  543.         return(SUCCESS);
  544.     }
  545.     if (ips_Debug) {
  546.         fprintf(stderr, "IP_Input: Fragment completes packet\n");
  547.     }
  548.     stats.ip.fragsReass++;
  549.     }
  550.  
  551.     /*
  552.      * IP Processing is now complete. Pass the datagram to the next protocol
  553.      * for additional processing.  If a callback has not been established for
  554.      * a protocol, give the datagram to the raw socket layer. 
  555.      */
  556.  
  557.     if ((ipHeaderPtr->protocol <= MAX_PROTOCOL_NUM) &&
  558.     (protocolCallback[ipHeaderPtr->protocol] != NULL)) {
  559.  
  560.      (*protocolCallback[ipHeaderPtr->protocol]) (netID, packetPtr);
  561.  
  562.     } else {
  563.     Raw_Input((int)ipHeaderPtr->protocol, ipHeaderPtr->source, 
  564.             ipHeaderPtr->dest, packetPtr);
  565.     return(FAILURE);    /* So caller will deallocate the packet. */
  566.     }
  567.     return(SUCCESS);
  568. }
  569.  
  570. /*
  571.  *----------------------------------------------------------------------
  572.  *
  573.  * FragTimeoutHandler --
  574.  *
  575.  *    Examines the fragment queue to see if any fragments should be
  576.  *    discarded because they have not been reassembled within a certain
  577.  *    amount of time. This routine is called from the Fs_Dispatch's
  578.  *    timeout mechanism.
  579.  *
  580.  * Results:
  581.  *    None.
  582.  *
  583.  * Side effects:
  584.  *    The fragment info list may be changed.
  585.  *
  586.  *----------------------------------------------------------------------
  587.  */
  588.  
  589. /*ARGSUSED*/
  590. static void
  591. FragTimeoutHandler(data, time)
  592.     ClientData    data;        /* ignored. */
  593.     Time    time;        /* ignored. */
  594. {
  595.     register DgramFragInfo    *fragInfoPtr;
  596.  
  597.     stats.ip.fragTimeouts++;
  598.  
  599.     fragInfoPtr = (DgramFragInfo *) List_First(&fragInfoList);
  600.     while (!List_IsAtEnd(&fragInfoList, (List_Links *) fragInfoPtr)) {
  601.     if (fragInfoPtr->timeToLive <= 0) {
  602.         /*
  603.          * FreeFragments will remove the element from the list
  604.          * but it will return the pointer to the next element
  605.          * so the while loop will work.
  606.          */
  607.  
  608.         if (ips_Debug) {
  609.         fprintf(stderr, "IP Frag timeout: src <%x, #%d>\n",
  610.             fragInfoPtr->source, fragInfoPtr->ident);
  611.         }
  612.  
  613.         fragInfoPtr = FreeFragments(fragInfoPtr);
  614.  
  615.         stats.ip.fragsTimedOut++;
  616.  
  617.     } else {
  618.         fragInfoPtr->timeToLive--;
  619.         fragInfoPtr = (DgramFragInfo *) 
  620.                 List_Next((List_Links *) fragInfoPtr);
  621.     }
  622.  
  623.     }
  624. }
  625.  
  626.  
  627. /*
  628.  *----------------------------------------------------------------------
  629.  *
  630.  * ReassemblePacket --
  631.  *
  632.  *    Given a packet that is a fragment of a datagram, try to reassemble
  633.  *    a complete datagram.
  634.  *
  635.  * Results:
  636.  *    TRUE        - the datagram was reassembled.
  637.  *    FALSE        - the fragment did not complete the datagram.
  638.  *
  639.  * Side effects:
  640.  *    The fragment will be added to the list of frgaments for this
  641.  *    datagram. If all fragments for the datagram have arrived, they
  642.  *    are consolidated into 1 buffer and the memory held by the fragments 
  643.  *    is freed.
  644.  *
  645.  *----------------------------------------------------------------------
  646.  */
  647.  
  648. static Boolean
  649. ReassemblePacket(fragInfoPtr, packetPtr)
  650.     register DgramFragInfo *fragInfoPtr;/* Info about existing fragments
  651.                      * for this datagram. */
  652.     IPS_Packet    *packetPtr;        /* Addr of ptr to Fragment (in) -- Addr
  653.                      * of ptr to completed datagram (out).*/
  654. {
  655.     register FragDataInfo    *dataPtr;    /* Ptr to element on the
  656.                          * fragment queue. */
  657.     register FragDataInfo    *newDataPtr;
  658.     register List_Links        *fragDataListPtr;
  659.     register Net_IPHeader    *ipHeaderPtr;
  660.     register int        fragOffset;
  661.     Address            ptr;
  662.     Boolean            first;
  663.     int                next;
  664.     int                lastByte;
  665.  
  666.     ipHeaderPtr = packetPtr->ipPtr;
  667.  
  668.     /*
  669.      * The fragOffset "is measured in units of 8 octets (64 bits)".
  670.      * It is necessary to use it as # of bytes, hence the multiplication
  671.      * by 8.  Note that we already byte swapped it before this routine was
  672.      * called.
  673.      */
  674.     fragOffset = ipHeaderPtr->fragOffset * 8;
  675.  
  676.     /*
  677.      * For the first fragment, allocate the fragment info data structure 
  678.      * and initialize it.
  679.      */
  680.     if (fragInfoPtr == (DgramFragInfo *) NULL) {
  681.     fragInfoPtr = (DgramFragInfo *) malloc(sizeof(DgramFragInfo));
  682.     fragInfoPtr->source    = ipHeaderPtr->source;
  683.     fragInfoPtr->dest    = ipHeaderPtr->dest;
  684.     fragInfoPtr->ident    = ipHeaderPtr->ident;
  685.     fragInfoPtr->protocol    = ipHeaderPtr->protocol;
  686.     fragInfoPtr->numFrags    = 0;
  687.     fragInfoPtr->timeToLive    = NET_IP_MAX_FRAG_TTL;
  688.     fragDataListPtr =  &(fragInfoPtr->dataList);
  689.     dataPtr = (FragDataInfo    *) fragDataListPtr;
  690.     List_Init(fragDataListPtr);
  691.  
  692.     List_InitElement((List_Links *) fragInfoPtr);
  693.     List_Insert((List_Links *) fragInfoPtr, LIST_ATFRONT(&fragInfoList));
  694.     } else {
  695.  
  696.     fragDataListPtr = &(fragInfoPtr->dataList);
  697.  
  698.     /*
  699.      * Insert a new fragment into the appropriate spot in the fragment
  700.      * list. Depending on the location, new fragments may or may not
  701.      * replace data in existing fragments.  (Note: this is contrary
  702.      * to RFC791 which says data in an arriving fragment should
  703.      * replace existing data. The algorithm to do that is a bit more
  704.      * complex than the one use below.)
  705.      *
  706.      * Step 1: search the list to find the first existing fragment
  707.      * that begins after the new fragment. When the loop is exited via
  708.      * the break, dataPtr will point to this existing fragment.
  709.      * If we don't take the break, dataPtr will point to the head of 
  710.      * the list and the new fragment belongs at the end of the list.
  711.      */
  712.  
  713.     LIST_FORALL(fragDataListPtr, (List_Links *) dataPtr) {
  714.         /*
  715.          * Find the first existing fragment that begins after 
  716.          * the new fragment.
  717.          */ 
  718.         if (fragOffset < dataPtr->fragOffset) {
  719.         break;
  720.         }
  721.     }
  722.  
  723.     /*
  724.      * Step 2: The new fragment is before dataPtr and after
  725.      * newDataPtr. newDataPtr could be the head of list which means
  726.      * the new fragment fits in front of all the other fragments.
  727.      * dataPtr could be the list head which means that the new
  728.      * fragment goes at the end of the list.
  729.      */
  730.  
  731.     newDataPtr = (FragDataInfo *) (List_Prev((List_Links *)dataPtr));
  732.  
  733.     if (!List_IsAtEnd(fragDataListPtr, (List_Links *)newDataPtr)) {
  734.  
  735.         int i = newDataPtr->fragOffset + newDataPtr->dataLen - 
  736.                 fragOffset;
  737.         /*
  738.          * "if (i > 0)" ==  if (fragOffset < last byte in preceeding 
  739.          * fragment) then the new fragment overlaps or is contained in 
  740.          * the preceeding fragment.
  741.          */
  742.  
  743.         if (i > 0) {
  744.         if (i >= ipHeaderPtr->totalLen) {
  745.             /*
  746.              * The new fragment is totally contained in the preceeding 
  747.              * fragment so drop the new fragment. 
  748.              *
  749.              * (If the new data were to replace the old, the preceeding 
  750.              * fragment would have to be split or the data from 
  751.              * the new fragment copied into the preceeding fragment.)
  752.              */
  753.  
  754.             if (ips_Debug) {
  755.             fprintf(stderr, "ReassemblePacket: Frag dropped\n");
  756.             }
  757.             stats.ip.fragsDropped++;
  758.             free(packetPtr->base);
  759.             return(FALSE);
  760.  
  761.         } else {
  762.             /*
  763.              * The end of the preceeding fragment needs to be trimmed 
  764.              * because the new fragment replaces that data.
  765.              * (4.3BSD keeps the old data and trims the front of
  766.              * the new fragment).
  767.              */
  768.              newDataPtr->dataLen -= i;
  769.         }
  770.         }
  771.     }
  772.  
  773.     /*
  774.      * Step 3:  see if the succeeding fragments need to be trimmed 
  775.      * because the end of the new fragment partially or completely 
  776.      * overlaps them.
  777.      */
  778.  
  779.     lastByte = fragOffset + ipHeaderPtr->totalLen;
  780.     while ((!List_IsAtEnd(fragDataListPtr, (List_Links *)dataPtr)) &&
  781.            (dataPtr->fragOffset < lastByte)) {
  782.  
  783.         if ((dataPtr->fragOffset + dataPtr->dataLen) < lastByte) {
  784.         /*
  785.          * The new fragment covers the old fragment so the
  786.          * old one can be freed.
  787.          */
  788.  
  789.         newDataPtr =  /* temp. holder */
  790.             (FragDataInfo *) (List_Next((List_Links *)dataPtr));
  791.         List_Remove((List_Links *)dataPtr);
  792.         free((char *) dataPtr->fragPacket.base);
  793.         free((char *) dataPtr);
  794.         dataPtr = newDataPtr;
  795.  
  796.         } else {
  797.         /*
  798.          * The new fragment covers some, but not all, of the old 
  799.          * fragment. Trim data from the start of the old one. 
  800.          * At this point we are also done trimming.
  801.          */
  802.         int trimAmt = lastByte - dataPtr->fragOffset;
  803.  
  804.         dataPtr->fragOffset    += trimAmt;
  805.         dataPtr->dataOffset    += trimAmt;
  806.         dataPtr->dataLen    -= trimAmt;
  807.         break;
  808.         }
  809.     }
  810.     }
  811.  
  812.     /*
  813.      * Insert the new fragment into the list of received fragments.
  814.      */
  815.  
  816.     fragInfoPtr->numFrags++;
  817.     newDataPtr = (FragDataInfo *) malloc(sizeof(FragDataInfo));
  818.     newDataPtr->fragOffset    = fragOffset;
  819.     newDataPtr->dataOffset    = ipHeaderPtr->headerLen * 4;
  820.     newDataPtr->dataLen        = ipHeaderPtr->totalLen -newDataPtr->dataOffset;
  821.     newDataPtr->fragPacket    = *packetPtr;
  822.  
  823.     List_InitElement((List_Links *) newDataPtr);
  824.     List_Insert((List_Links *)newDataPtr, LIST_BEFORE((List_Links *) dataPtr));
  825.  
  826.  
  827.     /*
  828.      * Now scan the data list for this datagram to see if all the 
  829.      * fragments have been received. "Next" is the next expected fragment
  830.      * offset.
  831.      */
  832.  
  833.     next = 0;
  834.     LIST_FORALL(fragDataListPtr, (List_Links *) dataPtr) {
  835.     if (dataPtr->fragOffset != next) {
  836.         /*
  837.          * Oops! Found a hole so the datagram is not yet complete.
  838.          */
  839.         if (ips_Debug) {
  840.         fprintf(stderr, "ReassemblePacket: Incomplete datagram\n");
  841.         }
  842.         return(FALSE);
  843.     } else {
  844.         next += dataPtr->dataLen;
  845.     }
  846.     }
  847.  
  848.     /*
  849.      * All the fragments are contiguous but we have to check if the
  850.      * last fragment has been received. This is done by checking 
  851.      * the NET_IP_MORE_FRAGS bit in the header of the queue's last fragment.
  852.      * If that bit is set, then the reassembly is not yet complete.
  853.      *
  854.      * (dataPtr should point to the head of the list so we need to look
  855.      * at the previous element.)
  856.      */
  857.  
  858.     newDataPtr = (FragDataInfo *) (List_Prev((List_Links *)dataPtr));
  859.     if (newDataPtr->fragPacket.ipPtr->flags & NET_IP_MORE_FRAGS) {
  860.     if (ips_Debug) {
  861.         fprintf(stderr, "ReassemblePacket: More frags\n");
  862.     }
  863.     return(FALSE);
  864.     }
  865.  
  866.     /*
  867.      * At this point, all the fragments have been received. A new buffer
  868.      * is allocated so all the fragments can be concatenated together into
  869.      * 1 datagram.  The datagram's IP header comes from the first fragment.
  870.      * After copying the fragment, the FragDatInfo element is removed from
  871.      * the list and freed, along with the fragment.
  872.      *
  873.      * (IPS_InitPacket will resuse packetPtr and allocate new memory. 
  874.      * We don't free(packetPtr->base) before calling IPS_InitPacket 
  875.      * because that buffer is already used in one of elements in the fragment 
  876.      * data list for this datagram.)
  877.      */
  878.  
  879.     if (ips_Debug) {
  880.     fprintf(stderr, "ReassemblePacket: All frags received\n");
  881.     }
  882.  
  883.     IPS_InitPacket(next, packetPtr);
  884.     ptr = packetPtr->dbase + sizeof(IPS_PacketNetHdr);
  885.     packetPtr->ipPtr = (Net_IPHeader *) ptr;
  886.  
  887.     first = TRUE;
  888.     dataPtr = (FragDataInfo *) List_First(fragDataListPtr);
  889.     while (!List_IsAtEnd(fragDataListPtr, (List_Links *) dataPtr)) {
  890.     if (first) {
  891.         int amtToCopy = dataPtr->fragPacket.ipPtr->totalLen;
  892.         first = FALSE;
  893.  
  894.         /*
  895.          * The header of the first fragment needs to be copied, too.
  896.          */
  897.         bcopy((Address) dataPtr->fragPacket.ipPtr, (Address) ptr,amtToCopy);
  898.  
  899.         /*
  900.          * Reset the size of the packet in the header.
  901.          */
  902.         packetPtr->ipLen = ((Net_IPHeader *) ptr)->totalLen = 
  903.                 next + (dataPtr->fragPacket.ipPtr->headerLen * 4);
  904.  
  905.         ptr += amtToCopy;
  906.     } else {
  907.         bcopy((Address) dataPtr->fragPacket.ipPtr+dataPtr->dataOffset, 
  908.             (Address) ptr, dataPtr->dataLen);
  909.         ptr += dataPtr->dataLen;
  910.     }
  911.  
  912.     newDataPtr = (FragDataInfo *) (List_Next((List_Links *)dataPtr));
  913.     List_Remove((List_Links *) dataPtr);
  914.     free((char *) dataPtr->fragPacket.base);
  915.     free((char *) dataPtr);
  916.     dataPtr = newDataPtr;
  917.     }
  918.     List_Remove((List_Links *) fragInfoPtr);
  919.     free((char *) fragInfoPtr);
  920.  
  921.     return(TRUE);
  922. }
  923.  
  924. /*
  925.  *----------------------------------------------------------------------
  926.  *
  927.  * FreeFragments --
  928.  *
  929.  *    Releases the fragments held while trying to reassemble a datagram.
  930.  *
  931.  * Results:
  932.  *    Address of the previous element in the fragInfoList.
  933.  *
  934.  * Side effects:
  935.  *    The saved packets are freed and the *fragInfoPtr is removed
  936.  *    from the fragment queue.
  937.  *
  938.  *----------------------------------------------------------------------
  939.  */
  940.  
  941. static DgramFragInfo *
  942. FreeFragments(fragInfoPtr)
  943.     register DgramFragInfo *fragInfoPtr; /* Info about existing fragments
  944.                       * for this datagram. */
  945. {
  946.     register List_Links    *dataPtr;
  947.     register List_Links    *nextPtr;
  948.     DgramFragInfo *savePtr; 
  949.  
  950.     /*
  951.      * We need to return the ptr to the next element so this routine
  952.      * can be called inside of a list-examining loop and still be able 
  953.      * to remove the element from the list.
  954.      */
  955.     savePtr = (DgramFragInfo *) List_Next((List_Links *) fragInfoPtr);
  956.     List_Remove((List_Links *) fragInfoPtr);
  957.  
  958.     LIST_FORALL(&(fragInfoPtr->dataList), dataPtr) {
  959.     nextPtr = List_Next(dataPtr);
  960.     List_Remove(dataPtr);
  961.     free((char *) ((FragDataInfo *)dataPtr)->fragPacket.base);
  962.     free((char *) dataPtr);
  963.     dataPtr = nextPtr;
  964.     }
  965.     free((char *) fragInfoPtr);
  966.     return(savePtr);
  967. }
  968.  
  969.  
  970. /*
  971.  *----------------------------------------------------------------------
  972.  *
  973.  * ForwardPacket --
  974.  *
  975.  *    Given an packet that's not for us, this routine determines which 
  976.  *    host the packet should be forwarded to and tries to send it to
  977.  *    that host (possibly via gateways).
  978.  *
  979.  *    For now, we don't do forwarding -- the packet is just dropped.
  980.  *    This will need to change when Sprite machines want to act
  981.  *    as gateways/routers.
  982.  *
  983.  *
  984.  * Results:
  985.  *    None.
  986.  *
  987.  * Side effects:
  988.  *    None.
  989.  *
  990.  *----------------------------------------------------------------------
  991.  */
  992.  
  993. /*ARGSUSED*/
  994. static void
  995. ForwardPacket(packetPtr)
  996.     IPS_Packet    *packetPtr;    /* Packet layout descriptor. */
  997. {
  998.     stats.ip.cannotForward++;
  999. }
  1000.  
  1001.  
  1002. /*
  1003.  *----------------------------------------------------------------------
  1004.  *
  1005.  * ProcessOptions --
  1006.  *
  1007.  *    This routine decodes the option(s) that follow the IP header
  1008.  *    and processes it/them.
  1009.  *
  1010.  * Results:
  1011.  *    None.
  1012.  *
  1013.  * Side effects:
  1014.  *    An ICMP packet is sent to the packet sender if if an option is 
  1015.  *    malformed. The Record Route and Timestamp options modify the
  1016.  *    the packet.
  1017.  *
  1018.  *----------------------------------------------------------------------
  1019.  */
  1020.  
  1021. static ReturnStatus
  1022. ProcessOptions(hdrLen, ipHeaderPtr)
  1023.     int hdrLen;                /* Header length in bytes. */
  1024.     register Net_IPHeader *ipHeaderPtr;    /* IP header with trailing options. */
  1025. {
  1026.     register Address optionPtr;        /* Ptr to the current option in the
  1027.                      * IP header that's being processed. */
  1028.     int        optionType;
  1029.     int        optionLen;
  1030.     int        totalOptionSize;
  1031.     int        ptr;
  1032.     int        icmpCode;
  1033.     int        icmpType;
  1034.  
  1035.  
  1036.     /*
  1037.      * Go through the option area of the packet and process each option.
  1038.      * The options begin just after the standard header info.
  1039.      */
  1040.     
  1041.     optionPtr = ((Address) ipHeaderPtr) + sizeof(Net_IPHeader) + 1;
  1042.  
  1043.     for (totalOptionSize = hdrLen - sizeof(Net_IPHeader); 
  1044.      totalOptionSize > 0; 
  1045.      totalOptionSize -= optionLen, optionPtr += optionLen) {
  1046.  
  1047.     optionType = optionPtr[NET_IP_OPT_TYPE_OFFSET];
  1048.  
  1049.     /*
  1050.      * Decode the option. END_OF_LIST and NOP options are only 1
  1051.      * octet long. The rest of the options have a length field that 
  1052.      * must be checked.
  1053.      */
  1054.  
  1055.     if (optionType == NET_IP_OPT_END_OF_LIST) {
  1056.         break;
  1057.     } else if (optionType == NET_IP_OPT_NOP) {
  1058.         optionLen = 1;
  1059.     } else {
  1060.         optionLen = optionPtr[NET_IP_OPT_LEN_OFFSET];
  1061.         if (optionLen <= 0 || optionLen > totalOptionSize) {
  1062.         icmpType = NET_ICMP_PARAM_PROB;
  1063.         icmpCode = &optionPtr[NET_IP_OPT_LEN_OFFSET] - 
  1064.                 (Address) ipHeaderPtr;
  1065.         goto bad;
  1066.         }
  1067.  
  1068.         switch (optionType) {
  1069.  
  1070.         /*
  1071.          * Loose and strict source routing and record options:
  1072.          *
  1073.          * If the packet is not directed towards one of our
  1074.          * Internet addresses then send an ICMP error packet if
  1075.          * strict routing is wanted or do nothing if loosely
  1076.          * routed.  Also, record our address in the option area
  1077.          * and make the next address in the routing list as the
  1078.          * destination.  If strictly-routed, make sure the next
  1079.          * address is on a directly-accessible network.
  1080.          */
  1081.  
  1082.         case NET_IP_OPT_LOOSE_ROUTE:
  1083.         case NET_IP_OPT_STRICT_ROUTE:
  1084.  
  1085.             ptr = optionPtr[NET_IP_OPT_PTR_OFFSET];
  1086.             if (ptr < NET_IP_OPT_MIN_PTR) {
  1087.             icmpType = NET_ICMP_PARAM_PROB;
  1088.             icmpCode = &optionPtr[NET_IP_OPT_PTR_OFFSET]  -
  1089.                     (Address) ipHeaderPtr;
  1090.             goto bad;
  1091.             }
  1092.  
  1093.             if (!Rte_AddrIsForUs(ipHeaderPtr->dest)) {
  1094.             if (optionType == NET_IP_OPT_STRICT_ROUTE) {
  1095.                 icmpType = NET_ICMP_UNREACHABLE;
  1096.                 icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1097.                 goto bad;
  1098.             }
  1099.             /*
  1100.              * Loose routing, and not at next destination
  1101.              * yet; nothing to do except forward.
  1102.              */
  1103.             break;
  1104.             }
  1105.  
  1106.             ptr--;            /* 0 origin */
  1107.             if (ptr > optionLen - sizeof(Net_InetAddress)) {
  1108.             /*
  1109.              * End of source route.  Should be for us.
  1110.              */
  1111.             SaveRoute(optionPtr, ipHeaderPtr->source);
  1112.  
  1113.             } else {
  1114.             Net_InetAddress addr;
  1115.  
  1116.             /*
  1117.              * We are an intermediate host in the routing list.
  1118.              * Change the packet's destination to the next host in 
  1119.              * the list and record our address there.
  1120.              */
  1121.             addr = *((Net_InetAddress *)(optionPtr + ptr));
  1122.                 
  1123.             if ((optionType == NET_IP_OPT_STRICT_ROUTE) && 
  1124.                 !CanForward(addr)) {
  1125.                 icmpType = NET_ICMP_UNREACHABLE;
  1126.                 icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1127.                 goto bad;
  1128.             }
  1129.             *((Net_InetAddress *)(optionPtr + ptr)) =
  1130.                     (ipHeaderPtr->dest);
  1131.             optionPtr[NET_IP_OPT_PTR_OFFSET] += 
  1132.                     sizeof(Net_InetAddress);
  1133.             ipHeaderPtr->dest = addr;
  1134.             }
  1135.             break;
  1136.  
  1137.  
  1138.         /*
  1139.          * Record Route option: 
  1140.          *
  1141.          *  Add our address in the area reserved for routes.
  1142.          */
  1143.  
  1144.         case NET_IP_OPT_REC_ROUTE: 
  1145.             {
  1146.             ptr = optionPtr[NET_IP_OPT_PTR_OFFSET];
  1147.             if (ptr < NET_IP_OPT_MIN_PTR) {
  1148.                 icmpType = NET_ICMP_PARAM_PROB;
  1149.                 icmpCode= &optionPtr[NET_IP_OPT_PTR_OFFSET]  -
  1150.                     (Address) ipHeaderPtr;
  1151.                 goto bad;
  1152.             }
  1153.  
  1154.             /*
  1155.              * If no space remains, do nothing.
  1156.              */
  1157.             ptr--;            /* 0 origin */
  1158.             if (ptr <= (optionLen - sizeof(Net_InetAddress))) {
  1159.                 /*
  1160.                  * See if we can forward this packet before our
  1161.                  * address is recorded in the routing list.
  1162.                  */
  1163.  
  1164.                 if (!CanForward(ipHeaderPtr->dest)) {
  1165.                     icmpType = NET_ICMP_UNREACHABLE;
  1166.                     icmpCode = NET_ICMP_UNREACH_SRC_ROUTE;
  1167.                     goto bad;
  1168.                 }
  1169.                 *((Net_InetAddress *)(optionPtr + ptr)) =
  1170.                  (Rte_GetOfficialAddr(FALSE));
  1171.  
  1172.                 optionPtr[NET_IP_OPT_PTR_OFFSET] += 
  1173.                     sizeof(Net_InetAddress);
  1174.             }
  1175.             }
  1176.             break;
  1177.  
  1178.         /*
  1179.          * Timestamp option: 
  1180.          *
  1181.          * Add a timestamp (and optionally our address) in the area 
  1182.          * reserved for it.
  1183.          */
  1184.  
  1185.         case NET_IP_OPT_TIMESTAMP: 
  1186.             {
  1187.             Net_InetTime    time;
  1188.             Net_InetAddress *addrPtr;
  1189.             Net_IPTimestampHdr *tsPtr =
  1190.                     (Net_IPTimestampHdr *)optionPtr;
  1191.  
  1192.             if (tsPtr->len < 5) {
  1193.                 icmpType = NET_ICMP_PARAM_PROB;
  1194.                 icmpCode = optionPtr - (Address) ipHeaderPtr;
  1195.                 goto bad;
  1196.             }
  1197.  
  1198.             if (tsPtr->pointer > (tsPtr->len - sizeof(*tsPtr))) {
  1199.                 tsPtr->overflow++;
  1200.                 if (tsPtr->overflow == 0) {
  1201.                 icmpType = NET_ICMP_PARAM_PROB;
  1202.                 icmpCode = optionPtr - (Address) ipHeaderPtr;
  1203.                 goto bad;
  1204.                 }
  1205.                 break;
  1206.             }
  1207.  
  1208.             addrPtr = (Net_InetAddress *)
  1209.                     (optionPtr + tsPtr->pointer -1);
  1210.  
  1211.             switch (tsPtr->flags) {
  1212.  
  1213.                 case NET_IP_OPT_TS_ONLY:
  1214.                 break;
  1215.  
  1216.                 /*
  1217.                  * Add our address to the packet if there's room.
  1218.                  */
  1219.                 case NET_IP_OPT_TS_AND_ADDR:
  1220.                 if ((tsPtr->pointer + sizeof(Net_InetTime) +
  1221.                     sizeof(Net_InetAddress)) > tsPtr->len) {
  1222.                     icmpType = NET_ICMP_PARAM_PROB;
  1223.                     icmpCode = optionPtr -
  1224.                             (Address) ipHeaderPtr;
  1225.                     goto bad;
  1226.                 }
  1227.                 *addrPtr = (Rte_GetOfficialAddr(FALSE));
  1228.                 tsPtr->pointer += sizeof(*addrPtr);
  1229.                 break;
  1230.  
  1231.                 /*
  1232.                  * Add our address to the packet only if our
  1233.                  * address in the list of prespecified addresses.
  1234.                  */
  1235.                 case NET_IP_OPT_TS_ADDR_SPEC:
  1236.                 if ((tsPtr->pointer + sizeof(Net_InetTime) +
  1237.                     sizeof(Net_InetAddress)) > tsPtr->len) {
  1238.  
  1239.                     icmpType = NET_ICMP_PARAM_PROB;
  1240.                     icmpCode = optionPtr - 
  1241.                             (Address) ipHeaderPtr;
  1242.                     goto bad;
  1243.                 }
  1244.                 if (!Rte_AddrIsForUs((*addrPtr))) {
  1245.                     continue;
  1246.                 }
  1247.                 tsPtr->pointer += sizeof(*addrPtr);
  1248.                 break;
  1249.  
  1250.                 default:
  1251.                     /*
  1252.                      * Unknown timestamp flag.
  1253.                      */
  1254.                     icmpType = NET_ICMP_PARAM_PROB;
  1255.                     icmpCode = optionPtr -(Address) ipHeaderPtr;
  1256.                     goto bad;
  1257.             }
  1258.             time = Net_HostToNetInt(IPS_GetTimestamp());
  1259.             bcopy( (Address)&time, 
  1260.                       (Address) (optionPtr + tsPtr->pointer -1),
  1261.                   sizeof(time));
  1262.             tsPtr->pointer += sizeof(time);
  1263.             }
  1264.             break;
  1265.  
  1266.         /*
  1267.          * The following options aren't handled yet.
  1268.          */
  1269.         case NET_IP_OPT_STREAM_ID:
  1270.         case NET_IP_OPT_SECURITY:
  1271.         default:
  1272.             break;
  1273.         }
  1274.     }
  1275.     }
  1276.     return(SUCCESS);
  1277.  
  1278.     /*
  1279.      * We are sent here if there was an error with an option's format.
  1280.      * Send an ICMP error packet to the source.
  1281.      */
  1282. bad:
  1283.     ICMP_SendErrorMsg(ipHeaderPtr, icmpType, icmpCode);
  1284.     return (FAILURE);
  1285. }
  1286.  
  1287.  
  1288. /*
  1289.  *----------------------------------------------------------------------
  1290.  *
  1291.  * CanForward --
  1292.  *
  1293.  *     Given an address of the next destination (final or next hop),
  1294.  *     indicate whether we can foraward the packet.
  1295.  *
  1296.  * Results:
  1297.  *    TRUE    - we are able to forward the packet.
  1298.  *    FALSE    - we are not able to forward the packet.
  1299.  *
  1300.  * Side effects:
  1301.  *    None.
  1302.  *
  1303.  *----------------------------------------------------------------------
  1304.  */
  1305.  
  1306. /*ARGSUSED*/
  1307. static Boolean
  1308. CanForward(dest)
  1309.      Net_InetAddress dest;
  1310. {
  1311.     /*
  1312.      * For now, say we can't forward anything.
  1313.      */
  1314.     return(FALSE);
  1315. }
  1316.  
  1317.  
  1318. /*
  1319.  * We need to save the IP options in case a higher-level protocol wants 
  1320.  * to respond to an incoming packet over the same route if the packet got
  1321.  * here using IP source routing.  This allows connection establishment and
  1322.  * maintenance when the remote end is on a network that is not known to us.
  1323.  *
  1324.  * MAX_SAVE_ADDRS is the max. # of IP addresses that can be stored in
  1325.  * an IP record route option. Subtract 3 for the record route info (type,
  1326.  * length and pointer).
  1327.  */
  1328.  
  1329. #define MAX_SAVE_ADDRS  ((NET_IP_OPT_MAX_LEN - 3)/sizeof(Net_InetAddress))
  1330. static struct {
  1331.     int numHops;                /* # of addresses in addr. */
  1332.     struct {
  1333.     struct {
  1334.         char    nop;        /* One NOP to align when 
  1335.                      * returning the route. */
  1336.         char    type;        /* Option type */
  1337.         char    len;        /* Totol length of info + addr. */
  1338.         char    ptr;        /* Offset where routes start. */
  1339.     } info;
  1340.     Net_InetAddress addr[MAX_SAVE_ADDRS];    /* List of routes. */
  1341.     } route;
  1342.     Net_InetAddress     dest;        /* In host byte order. */
  1343. } savedSrcRoute = { 0, {{NET_IP_OPT_NOP,}, }, };
  1344.  
  1345. /*
  1346.  *----------------------------------------------------------------------
  1347.  *
  1348.  * SaveRoute --
  1349.  *
  1350.  *    Save incoming source route for use in replies,
  1351.  *    to be picked up later by IP_SrcRoute if the receiver is interested.
  1352.  *    The options are kept in network byte order.
  1353.  *
  1354.  *
  1355.  * Results:
  1356.  *    None.
  1357.  *
  1358.  * Side effects:
  1359.  *    The route is stored in a static buffer.
  1360.  *
  1361.  *----------------------------------------------------------------------
  1362.  */
  1363.  
  1364. static void
  1365. SaveRoute(optionPtr, dest)
  1366.     Address    optionPtr;    /* Ptr to IP options buffer containing source
  1367.                  * routing option. */
  1368.     Net_InetAddress dest;    /* Next destination address to put in the
  1369.                  * saved source route. */
  1370. {
  1371.     int optLen;
  1372.  
  1373.     optLen = optionPtr[NET_IP_OPT_LEN_OFFSET];
  1374.     if (optLen > sizeof(savedSrcRoute.route) - 1) {
  1375.     (void) fprintf(stderr, "Warning: SaveRoute (IP): optLen (%d) bad\n", optLen);
  1376.     return;
  1377.     }
  1378.     bcopy(optionPtr, (Address)&savedSrcRoute.route.info.type, optLen);
  1379.     savedSrcRoute.numHops = (optLen - 3) / sizeof(Net_InetAddress);
  1380.     savedSrcRoute.dest = dest;
  1381. }
  1382.  
  1383.  
  1384. /*
  1385.  *----------------------------------------------------------------------
  1386.  *
  1387.  * IP_GetSrcRoute --
  1388.  *
  1389.  *    Get the incoming source route that was saved in savedSrcRoute
  1390.  *    for use in replies. The first hop is returned in *destPtr.
  1391.  *
  1392.  * Results:
  1393.  *    The address of a buffer containing the saved source route from the
  1394.  *    most recent IP packet.
  1395.  *
  1396.  * Side effects:
  1397.  *    None.
  1398.  *
  1399.  *----------------------------------------------------------------------
  1400.  */
  1401.  
  1402. Address 
  1403. IP_GetSrcRoute(lenPtr, destPtr)
  1404.     int    *lenPtr;        /* Out: Size of source-route buffer. */
  1405.     Net_InetAddress *destPtr;    /* Out: address of the first destination. */
  1406. {
  1407.     register Net_InetAddress *oldPtr, *newPtr;
  1408.     register Address routePtr;
  1409.     int    len;
  1410.  
  1411.     if (savedSrcRoute.numHops == 0) {
  1412.     *lenPtr = 0;
  1413.     return((Address) NULL);
  1414.     }
  1415.  
  1416.     len = ((1 + savedSrcRoute.numHops) * sizeof(Net_InetAddress)) +
  1417.         sizeof(savedSrcRoute.route.info);
  1418.     *lenPtr = len;
  1419.  
  1420.     /*
  1421.      * Allocate a buffer to hold the source route.
  1422.      */
  1423.     routePtr = malloc((unsigned int) len);
  1424.  
  1425.     /*
  1426.      * First the save first hop for return route.
  1427.      */
  1428.     *destPtr = savedSrcRoute.dest;
  1429.  
  1430.     /*
  1431.      * Copy the route info.
  1432.      */
  1433.     bcopy( (Address) &savedSrcRoute.route.info, routePtr,
  1434.         sizeof(savedSrcRoute.route.info));
  1435.     newPtr = (Net_InetAddress *) (routePtr + sizeof(savedSrcRoute.route.info));
  1436.                 
  1437.     /*
  1438.      * Record return path as an IP source route, reversing the path.
  1439.      */
  1440.     oldPtr = &savedSrcRoute.route.addr[savedSrcRoute.numHops -1];
  1441.     while (oldPtr >= savedSrcRoute.route.addr) {
  1442.     *newPtr++ = *oldPtr--;
  1443.     }
  1444.     return(routePtr);
  1445. }
  1446.  
  1447.  
  1448. /*
  1449.  *----------------------------------------------------------------------
  1450.  *
  1451.  * IP_Output --
  1452.  *
  1453.  *    Causes an IP packet to sent to the network. The packet may be
  1454.  *    fragmented if it's too large for the chosen network.
  1455.  *
  1456.  * Results:
  1457.  *    SUCCESS            - the datagram was sent out.
  1458.  *    FS_BUFFER_TOO_BIG    - the datagram was too large and had to be
  1459.  *                  fragmented but the DONT_FRAG bit was set
  1460.  *                  in the header.
  1461.  *    NET_UNREACHABLE        - couldn't find a network to send the datagram
  1462.  *                  to.
  1463.  *
  1464.  * Side effects:
  1465.  *    Packet(s) may be output.
  1466.  *
  1467.  *----------------------------------------------------------------------
  1468.  */
  1469.  
  1470. ReturnStatus
  1471. IP_Output(packetPtr, canTrash)
  1472.     register IPS_Packet *packetPtr;    /* Packet layout descriptor. IP-related
  1473.                      * fields are filled in. If the packet
  1474.                      * is fragmented, the data and hdrLen
  1475.                      * fields are modified. */
  1476.     Boolean canTrash;            /* TRUE if the packet will be discarded
  1477.                      * after output.  If so, then we can
  1478.                      * optimize fragmentation by writing
  1479.                      * packet headers over some data. */
  1480. {
  1481.     ReturnStatus    status;
  1482.     int            headerLenInBytes;
  1483.     int            maxOutSize;
  1484.     Rte_NetID        netID;
  1485.     register Net_IPHeader *headerPtr = packetPtr->ipPtr;
  1486.  
  1487.  
  1488.     headerLenInBytes = headerPtr->headerLen * 4;
  1489.  
  1490.     if (headerLenInBytes > NET_IP_MAX_HDR_SIZE) {
  1491.     return(FAILURE);
  1492.     }
  1493.  
  1494.  
  1495.     /*
  1496.      * Determine which network interface must be used to output this
  1497.      * datagram.
  1498.      */
  1499.  
  1500.     if (!Rte_FindOutputNet(headerPtr->dest,  &netID, &maxOutSize)) {
  1501.     return(NET_UNREACHABLE_NET);
  1502.     }
  1503.  
  1504. #ifdef notdef
  1505.     headerPtr->source = Net_HostToNetInt(headerPtr->source);
  1506.     headerPtr->dest   = Net_HostToNetInt(headerPtr->dest);
  1507. #endif
  1508.  
  1509.     /*
  1510.      * See if the datagram is small enough to be sent in 1 piece.
  1511.      */
  1512.  
  1513.     if (headerPtr->totalLen <= maxOutSize) {
  1514.     int    totalLen;
  1515.  
  1516.     stats.ip.wholeSent++;
  1517.     totalLen = headerPtr->totalLen;
  1518.     headerPtr->totalLen = Net_HostToNetShort(totalLen);
  1519.     headerPtr->fragOffset = 0;
  1520.     headerPtr->flags = 0;
  1521.     headerPtr->checksum = 0;
  1522.     headerPtr->checksum = Net_InetChecksum(headerLenInBytes, 
  1523.                     (Address) headerPtr);
  1524.     packetPtr->ipLen = headerLenInBytes;
  1525.     status = Rte_OutputPacket(netID, packetPtr);
  1526.  
  1527.     } else if (headerPtr->flags & NET_IP_DONT_FRAG) {
  1528.     /*
  1529.      * The datagram is too big but the higher-level protocol doesn't want
  1530.      * it to be fragmented. Better tell the sender that it's too big.
  1531.      */
  1532.  
  1533.     stats.ip.dontFragment++;
  1534.  
  1535.     status = FS_BUFFER_TOO_BIG;
  1536.     } else {
  1537.  
  1538.     register Address fragPtr;
  1539.     register Address dataPtr;
  1540.     int        totalDataLen;
  1541.     int        fragDataLen;
  1542.     int        fragHdrLen;
  1543.     int        offset;
  1544.     IPS_Packet     packet;
  1545.     char        ipHeader[NET_IP_MAX_HDR_SIZE];
  1546.  
  1547.     stats.ip.fragOnSend++;
  1548.  
  1549.     /*
  1550.      * The datagram is too big to send as 1 packet on the network
  1551.      * (identified by netID) but we can fragment the datagram into 
  1552.      * several packets and send them out individually. 
  1553.      *
  1554.      * Each fragment contains an IP header based on the original
  1555.      * header plus some portion of the data.  Options in the IP header
  1556.      * require special handling. All options in the original header
  1557.      * need to go in the first fragment's header.  In succeeding
  1558.      * fragments, only some of the options are included in the header.
  1559.      *
  1560.      * TotalDataLen is the number of bytes of data in the datagram and
  1561.      * fragDataLen is the amount of data that can fit into a fragment.
  1562.      * Actually fragDataLen must be a multiple of 8 (c.f. p. 25 in RFC791);
  1563.      * this done by masking off the low-order 3 bits.
  1564.      */
  1565.  
  1566.     totalDataLen = headerPtr->totalLen - headerLenInBytes;
  1567.     fragDataLen = (maxOutSize - headerLenInBytes) & ~7;
  1568.  
  1569.     /*
  1570.      * Output the first fragment. We use the orginal datagram by modifying 
  1571.      * the header and telling the output routine how many bytes to output 
  1572.      * so we can avoid copying.
  1573.      */
  1574.  
  1575.     headerPtr->flags = NET_IP_MORE_FRAGS;
  1576.     headerPtr->fragOffset = 0;
  1577.     SWAP_FRAG_OFFSET_HOST_TO_NET(headerPtr);
  1578.  
  1579.     headerPtr->totalLen = Net_HostToNetShort(fragDataLen+headerLenInBytes);
  1580.     headerPtr->checksum = 0;
  1581.     headerPtr->checksum = Net_InetChecksum(headerLenInBytes, 
  1582.                     (Address) headerPtr);
  1583.     packetPtr->dataLen = fragDataLen;
  1584.     packetPtr->ipLen = headerLenInBytes;
  1585.  
  1586.     /*
  1587.      * Reset the packet's higher-level protocol header length to 0.
  1588.      * That header is now considered part of the data.
  1589.      */
  1590.     packetPtr->hdrLen = 0;
  1591.     status = Rte_OutputPacket(netID, packetPtr);
  1592.     stats.ip.fragsSent++;
  1593.     if (status != SUCCESS) {
  1594.         return(status);
  1595.     }
  1596.  
  1597.     /*
  1598.      * The first fragDataLen bytes have been sent. DataPtr is set to
  1599.      * point to the next byte in the original datagram to be sent.
  1600.      */
  1601.     dataPtr = (Address) (((Address) headerPtr) + headerLenInBytes + 
  1602.                 fragDataLen);
  1603.  
  1604.     /*
  1605.      * Now allocate a buffer that will be used to send the rest of the
  1606.      * fragments.  We must over-allocate the space because we don't
  1607.      * know how much room the header options need until we copy them
  1608.      * (only some options are copied). The rest of the buffer will 
  1609.      * hold part of the data from the original packet.  We reuse this 
  1610.      * buffer for all remaining fragments, adjusting the header if 
  1611.      * necessary.
  1612.      *
  1613.      * CAN_TRASH:  If we can trash the packet then we do so by writing
  1614.      * the fragment headers over existing data.  This eliminates the
  1615.      * need to allocate a buffer and copy data into it.  The variable
  1616.      * dataPtr always references the next data byte to be output.
  1617.      * packet.base is set to be in front of this enough to fit the header.
  1618.      */
  1619.  
  1620. #define fragHdrPtr ((Net_IPHeader *)fragPtr)
  1621.  
  1622.     packet.totalLen = fragDataLen + headerLenInBytes + 
  1623.                    sizeof(IPS_PacketNetHdr);
  1624.     packet.hdrLen = 0;
  1625.     if (!canTrash) {
  1626.         /*
  1627.          * Allocate a packet buffer and copy the header into it.  Note that
  1628.          * we add two the allocated pointer so that we four byte align
  1629.          * everything but the 14 byte ethernet header.
  1630.          */
  1631.         packet.base = malloc((unsigned int) packet.totalLen + 2);
  1632.         packet.dbase = packet.base + 2;
  1633.         fragPtr = packet.dbase + sizeof(IPS_PacketNetHdr);
  1634.         fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, 
  1635.                     (Net_IPHeader *)fragPtr);
  1636.         packet.ipPtr = fragHdrPtr;
  1637.         fragHdrPtr->headerLen = fragHdrLen / 4;
  1638.     } else {
  1639.         /*
  1640.          * Just save the fragment header and get its length.
  1641.          */
  1642.         fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, ipHeader);
  1643.     }
  1644.     packet.ipLen = fragHdrLen;
  1645.  
  1646.     for (offset = fragDataLen; 
  1647.          offset < totalDataLen; 
  1648.          offset += fragDataLen, dataPtr += fragDataLen) {
  1649.  
  1650.         if (canTrash) {
  1651.         /*
  1652.          * Copy the fragment header in front of the next data to go out.
  1653.          */
  1654.         fragPtr = dataPtr - fragHdrLen;
  1655.         bcopy((char *)ipHeader, fragPtr, fragHdrLen);
  1656.         packet.base = packet.dbase = fragPtr - sizeof(IPS_PacketNetHdr);
  1657.         packet.ipPtr = fragHdrPtr;
  1658.         fragHdrPtr->headerLen = fragHdrLen / 4;
  1659.         }
  1660.         if (offset + fragDataLen >= totalDataLen) {
  1661.         /*
  1662.          * Last fragment reached. Must turn off MORE_FRAGS so the
  1663.          * receiver won't expect more data.
  1664.          */
  1665.         fragDataLen =  totalDataLen - offset;
  1666.         fragHdrPtr->flags = 0;
  1667.         } else {
  1668.         fragHdrPtr->flags = NET_IP_MORE_FRAGS;
  1669.         }
  1670.         fragHdrPtr->fragOffset = offset >> 3;
  1671.         SWAP_FRAG_OFFSET_HOST_TO_NET(fragHdrPtr);
  1672.  
  1673.         fragHdrPtr->totalLen = Net_HostToNetShort(fragDataLen + fragHdrLen);
  1674.  
  1675.  
  1676.         if (!canTrash) {
  1677.         /*
  1678.          * Copy the data into the extra packet.
  1679.          */
  1680.         bcopy( (Address) dataPtr, 
  1681.             (Address) fragPtr+fragHdrLen, fragDataLen);
  1682.         }
  1683.  
  1684.         fragHdrPtr->checksum = 0;
  1685.         fragHdrPtr->checksum = Net_InetChecksum(fragHdrLen, 
  1686.                         (Address) fragHdrPtr);
  1687.         packet.data = fragPtr + packet.ipLen;
  1688.         packet.dataLen = fragDataLen;
  1689.         status = Rte_OutputPacket(netID, &packet);
  1690.         stats.ip.fragsSent++;
  1691.         if (status != SUCCESS) {
  1692.         break;
  1693.         }
  1694.     }
  1695.     if (!canTrash) {
  1696.         free(packet.base);
  1697.     }
  1698.     }
  1699.     return (status);
  1700. }
  1701.  
  1702.  
  1703. /*
  1704.  *----------------------------------------------------------------------
  1705.  *
  1706.  * IP_QueueOutput --
  1707.  *
  1708.  *    Queues up a packet to be sent at a later time by IP_DelayedOutput.
  1709.  *
  1710.  * Results:
  1711.  *    None.
  1712.  *
  1713.  * Side effects:
  1714.  *    A queued packet may be sent.
  1715.  *    The packet is freed once IP_Output is called.
  1716.  *
  1717.  *----------------------------------------------------------------------
  1718.  */
  1719.  
  1720. static IPS_Packet queuedPacket;
  1721. static Boolean     isPacketQueued = FALSE;
  1722.  
  1723. void
  1724. IP_QueueOutput(packetPtr)
  1725.     IPS_Packet *packetPtr;    /* Packet layout descriptor. */
  1726. {
  1727.     if (isPacketQueued) {
  1728.     isPacketQueued = FALSE;
  1729.     (void) IP_Output(&queuedPacket, TRUE);
  1730.     free(queuedPacket.base);
  1731.  
  1732.     (void) IP_Output(packetPtr, TRUE);
  1733.     free(packetPtr->base);
  1734.     } else {
  1735.     isPacketQueued = TRUE;
  1736.     queuedPacket = *packetPtr;
  1737.     }
  1738. }
  1739.  
  1740.  
  1741. /*
  1742.  *----------------------------------------------------------------------
  1743.  *
  1744.  * IP_DelayedOutput --
  1745.  *
  1746.  *    Causes a queued IP packet to be output.
  1747.  *
  1748.  * Results:
  1749.  *    None.
  1750.  *
  1751.  * Side effects:
  1752.  *    The packet is freed once IP_Output is called.
  1753.  *
  1754.  *----------------------------------------------------------------------
  1755.  */
  1756.  
  1757. void
  1758. IP_DelayedOutput()
  1759. {
  1760.     if (isPacketQueued) {
  1761.     isPacketQueued = FALSE;
  1762.     (void) IP_Output(&queuedPacket, TRUE);
  1763.     free(queuedPacket.base);
  1764.     }
  1765. }
  1766.  
  1767.  
  1768. /*
  1769.  *----------------------------------------------------------------------
  1770.  *
  1771.  * CopyHeader --
  1772.  *
  1773.  *    Copies the IP header from a unfragmented datagram to a fragmented
  1774.  *    datagram. The basic IP header is copied from the source datagram 
  1775.  *    along with some of the options to the destination datagram.
  1776.  *    According to RFC791, only certain options are copied to fragment
  1777.  *    headers.
  1778.  *
  1779.  * Results:
  1780.  *    The length in bytes of the copied header.
  1781.  *
  1782.  * Side effects:
  1783.  *    None.
  1784.  *
  1785.  *----------------------------------------------------------------------
  1786.  */
  1787.  
  1788. static int
  1789. CopyHeader(srcHdrLen, srcHdrPtr, destHdrPtr)
  1790.     int        srcHdrLen;        /* # of bytes in the src header. */
  1791.     Net_IPHeader *srcHdrPtr;        /* Ptr to original datagram header. */
  1792.     Net_IPHeader *destHdrPtr;        /* Ptr to fragment datagram header. */
  1793. {
  1794.     register unsigned char *srcPtr;    /* Ptr to the source's options area. */
  1795.     register unsigned char *destPtr;    /* Ptr to the dest's options area. */
  1796.     int        optionAreaLen;        /* # of bytes of options that have been
  1797.                      * copied from the source to dest. */
  1798.     int        option;            /* Current option. */
  1799.     int        optionLen;        /* Lenght in bytes of current option.*/
  1800.  
  1801.     /*
  1802.      * First copy the basic IP header that is required for every IP datagram.
  1803.      */
  1804.     *destHdrPtr = *srcHdrPtr;
  1805.  
  1806.     /*
  1807.      * Now selectively copy options from the source packet to the dest
  1808.      * packet header. The dest packet is a fragment and only some of the
  1809.      * options need to be copied to it.
  1810.      */
  1811.     srcPtr  = (unsigned char *)((Address)srcHdrPtr  + sizeof(Net_IPHeader));
  1812.     destPtr = (unsigned char *)((Address)destHdrPtr + sizeof(Net_IPHeader));
  1813.  
  1814.     optionAreaLen = srcHdrLen - sizeof(Net_IPHeader);
  1815.  
  1816.     for ( ; optionAreaLen > 0; optionAreaLen -= optionLen, srcPtr += optionLen){
  1817.         option = srcPtr[0];
  1818.         if (option == NET_IP_OPT_END_OF_LIST) {
  1819.         break;
  1820.         }
  1821.         if (option == NET_IP_OPT_NOP) {
  1822.         optionLen = 1;
  1823.         } else {
  1824.         optionLen = srcPtr[NET_IP_OPT_LEN_OFFSET];
  1825.         }
  1826.  
  1827.         if (optionLen > optionAreaLen) {
  1828.         (void) fprintf(stderr, 
  1829.             "Warning: (IP) CopyOption: bad option length %d\n", 
  1830.             optionLen);
  1831.         optionLen = optionAreaLen;
  1832.         }
  1833.  
  1834.         /*
  1835.          * Copy the option if it's supposed to be copied.
  1836.          */
  1837.         if (NET_IP_OPT_COPIED(option)) {
  1838.         bcopy((Address)srcPtr, (Address)destPtr, optionLen);
  1839.         destPtr += optionLen;
  1840.         }
  1841.     }
  1842.  
  1843.     /*
  1844.      * Pad the options area in the dest. packet with END_OF_LIST until 
  1845.      * a 32-bit boundary is reached.
  1846.      */
  1847.     for (optionLen = destPtr - (unsigned char *)(destHdrPtr+1); 
  1848.          optionLen & 0x3; optionLen++) {
  1849.     *destPtr++ = NET_IP_OPT_END_OF_LIST;
  1850.     }
  1851.  
  1852.     /*
  1853.      * Return the true size of the dest.'s datagram header.
  1854.      */
  1855.     return(sizeof(Net_IPHeader) + optionLen);
  1856. }
  1857.  
  1858.  
  1859. /*
  1860.  *----------------------------------------------------------------------
  1861.  *
  1862.  * IP_FormatPacket --
  1863.  *
  1864.  *    Given a partially-formed packet, this routine fills in most
  1865.  *    of the fields in the IP header and computes a checksum for
  1866.  *    the header. After this routine completes, the packet can be
  1867.  *    sent out on the network.
  1868.  *
  1869.  * Results:
  1870.  *    None.
  1871.  *
  1872.  * Side effects:
  1873.  *    All IP fields in the packet are modified.
  1874.  *
  1875.  *----------------------------------------------------------------------
  1876.  */
  1877.  
  1878. void
  1879. IP_FormatPacket(protocol, timeToLive, srcAddr, destAddr, packetPtr)
  1880.     int            protocol;    /* Assigned protocol #. */
  1881.     int            timeToLive;    /* # of seconds before packet should
  1882.                      * be discarded. Value depends on
  1883.                      * the protocol. */
  1884.     Net_InetAddress    srcAddr;    /* One of our IP addresses. */
  1885.     Net_InetAddress    destAddr;    /* Where to send the packet. */
  1886.     register IPS_Packet *packetPtr;    /* Partially formed packet. */
  1887. {
  1888.     register Net_IPHeader    *ipPtr;
  1889.     static int    ident = 0;
  1890.  
  1891.     /*
  1892.      * Fill in the IP-specific stuff in the packet.
  1893.      */
  1894.     packetPtr->ipLen = sizeof(Net_IPHeader);
  1895.     if (packetPtr->hdrLen > 0) {
  1896.     ipPtr = packetPtr->ipPtr = (Net_IPHeader *) 
  1897.             (((Address)packetPtr->hdr.hdrPtr) - packetPtr->ipLen);
  1898.     } else {
  1899.     ipPtr = packetPtr->ipPtr = (Net_IPHeader *) 
  1900.             (packetPtr->data - packetPtr->ipLen);
  1901.     }
  1902.  
  1903.     /*
  1904.      * Fill in the IP header and checksum it.
  1905.      */
  1906.     ipPtr->version    = NET_IP_VERSION;
  1907.     ipPtr->headerLen    = sizeof(Net_IPHeader) / 4;
  1908.     ipPtr->typeOfService = 0;
  1909.     ipPtr->totalLen    = sizeof(Net_IPHeader) + packetPtr->hdrLen + 
  1910.                 packetPtr->dataLen;
  1911.     ipPtr->ident    = Net_HostToNetShort(ident);
  1912.     ident += 1;
  1913.     ipPtr->fragOffset    = 0;
  1914.     ipPtr->flags    = 0;
  1915.     ipPtr->timeToLive    = timeToLive;
  1916.     ipPtr->protocol    = protocol;
  1917.     ipPtr->source    = srcAddr;
  1918.     ipPtr->dest        = destAddr;
  1919.     ipPtr->checksum    = 0;
  1920.     ipPtr->checksum    = Net_InetChecksum(sizeof(Net_IPHeader),(Address)ipPtr);
  1921. }
  1922.  
  1923.  
  1924. /*
  1925.  *----------------------------------------------------------------------
  1926.  *
  1927.  * TestInputProc --
  1928.  *
  1929.  *    Debugging code to print the header of an IP datagram.
  1930.  *
  1931.  * Results:
  1932.  *    None.
  1933.  *
  1934.  * Side effects:
  1935.  *    None.
  1936.  *
  1937.  *----------------------------------------------------------------------
  1938.  */
  1939.  
  1940. #ifdef DEBUG
  1941.  
  1942. static char srcAddr[18];
  1943. static char destAddr[18];
  1944. static char *ProtNumToName();
  1945.  
  1946. /*ARGSUSED*/
  1947. static void
  1948. TestInputProc(netID, packetPtr)
  1949.     Rte_NetID    netID;
  1950.     IPS_Packet    *packetPtr;
  1951. {
  1952.     register Net_IPHeader       *headerPtr;
  1953.     unsigned short        checksum;
  1954.  
  1955.     headerPtr = packetPtr->ipPtr;
  1956.  
  1957.     (void) fflush(stdout);
  1958.  
  1959.     (void) Net_InetAddrToString(headerPtr->source, srcAddr);
  1960.     (void) Net_InetAddrToString(headerPtr->dest, destAddr);
  1961.  
  1962.     (void) printf("IP Packet: size = %d\n", packetPtr->ipLen);
  1963.     (void) printf("Protocol, version:    %s, %d\n", 
  1964.             ProtNumToName(headerPtr->protocol),
  1965.             headerPtr->version);
  1966.     (void) printf("Src, dest addrs:    %s, %s\n", srcAddr, destAddr);
  1967.  
  1968.     (void) printf("Header, total len:    %d, %d\n", 
  1969.             headerPtr->headerLen, headerPtr->totalLen);
  1970.     (void) printf("TOS, ttl:        %x, %d\n", 
  1971.             headerPtr->typeOfService, headerPtr->timeToLive);
  1972.     checksum = headerPtr->checksum, 
  1973.     headerPtr->checksum = 0;
  1974.     (void) printf("checksum, recomp:    %x, %x\n", checksum, 
  1975.         Net_InetChecksum((int)headerPtr->headerLen*4, 
  1976.                     (Address)headerPtr));
  1977.     (void) printf("Frag flags, offset, ID:    %x, %d, %x\n", 
  1978.             headerPtr->flags, headerPtr->fragOffset, 
  1979.             headerPtr->ident);
  1980.     (void) printf("\n");
  1981.  
  1982.     (void) fflush(stdout);
  1983.  
  1984.     free(packetPtr->base);
  1985.     return;
  1986. }
  1987.  
  1988. static char *
  1989. ProtNumToName(num) 
  1990.     unsigned char num;
  1991. {
  1992.     static char buffer[5];
  1993.  
  1994.     switch (num) {
  1995.     case NET_IP_PROTOCOL_IP:
  1996.         return("IP");
  1997.     case NET_IP_PROTOCOL_ICMP:
  1998.         return("ICMP");
  1999.     case NET_IP_PROTOCOL_TCP:
  2000.         return("TCP");
  2001.     case NET_IP_PROTOCOL_EGP:
  2002.         return("EGP");
  2003.     case NET_IP_PROTOCOL_UDP:
  2004.         return("UDP");
  2005.     default:
  2006. #ifndef KERNEL
  2007.         (void) sprintf(buffer, "%4d", num);
  2008.         return(buffer);
  2009. #else
  2010.         return("???");
  2011. #endif
  2012.     }
  2013. }
  2014. #endif DEBUG
  2015. @
  2016.  
  2017.  
  2018. 1.8
  2019. log
  2020. @Added IP_AcceptedProtocol and some #ifdef KERNEL
  2021. @
  2022. text
  2023. @d32 1
  2024. a32 1
  2025. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/ip.c,v 1.7 89/02/21 10:13:07 brent Exp $ SPRITE (Berkeley)";
  2026. d135 15
  2027. d341 4
  2028. d353 4
  2029. d370 3
  2030. d378 1
  2031. a378 4
  2032. #ifdef notdef
  2033.     ipHeaderPtr->source   = Net_NetToHostInt(ipHeaderPtr->source);
  2034.     ipHeaderPtr->dest     = Net_NetToHostInt(ipHeaderPtr->dest);
  2035. #endif
  2036. d389 4
  2037. d401 3
  2038. d408 13
  2039. d428 3
  2040. d451 4
  2041. d471 3
  2042. d483 3
  2043. d546 5
  2044. d609 2
  2045. a610 1
  2046.      * by 8.
  2047. d612 1
  2048. a613 2
  2049.     fragOffset = Net_NetToHostShort(ipHeaderPtr->fragOffset) * 8;
  2050.  
  2051. d692 3
  2052. d777 3
  2053. d798 3
  2054. d817 4
  2055. d1458 1
  2056. d1513 1
  2057. a1513 1
  2058.     headerPtr->flags |= NET_IP_MORE_FRAGS;
  2059. d1515 2
  2060. d1565 3
  2061. a1567 1
  2062.          * Allocate a packet buffer and copy the header into it.
  2063. d1569 2
  2064. a1570 1
  2065.         packet.base = packet.dbase = malloc((unsigned int) packet.totalLen);
  2066. d1580 1
  2067. a1580 1
  2068.         fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, &ipHeader);
  2069. d1593 2
  2070. a1594 3
  2071.         bcopy((char *)&ipHeader, fragPtr, fragHdrLen);
  2072.         packet.base = packet.dbase = dataPtr -
  2073.                     (fragHdrLen + sizeof(IPS_PacketNetHdr));
  2074. d1604 3
  2075. a1606 1
  2076.         fragHdrPtr->flags &= ~NET_IP_MORE_FRAGS;
  2077. d1608 3
  2078. a1612 1
  2079.         fragHdrPtr->fragOffset = Net_HostToNetShort(offset >> 3);
  2080. @
  2081.  
  2082.  
  2083. 1.7
  2084. log
  2085. @Added IP_MemBin
  2086. Changed fragmentation so it is done in place instead of
  2087. by copying data into a new buffer.
  2088. @
  2089. text
  2090. @d32 1
  2091. a32 1
  2092. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/ip.c,v 1.6 88/09/15 09:33:18 mendel Exp Locker: mendel $ SPRITE (Berkeley)";
  2093. a46 1
  2094. #include <stdio.h>
  2095. d239 32
  2096. d1861 1
  2097. d1864 3
  2098. @
  2099.  
  2100.  
  2101. 1.6
  2102. log
  2103. @Added/removed byte swapping for SPUR.
  2104. @
  2105. text
  2106. @d32 1
  2107. a32 1
  2108. static char rcsid[] = "$Header: ip.c,v 1.5 88/08/26 16:34:36 mendel Exp $ SPRITE (Berkeley)";
  2109. d140 26
  2110. d1304 1
  2111. a1304 1
  2112. IP_Output(packetPtr)
  2113. d1309 4
  2114. d1377 1
  2115. d1442 6
  2116. d1453 1
  2117. a1453 2
  2118.                sizeof(IPS_PacketNetHdr);
  2119.     packet.base = packet.dbase = malloc((unsigned int) packet.totalLen);
  2120. d1455 16
  2121. a1470 6
  2122.     fragPtr = packet.dbase + sizeof(IPS_PacketNetHdr);
  2123.     packet.ipPtr = fragHdrPtr;
  2124.  
  2125.     fragHdrLen = CopyHeader(headerLenInBytes, headerPtr, 
  2126.                 (Net_IPHeader *)fragPtr);
  2127.     fragHdrPtr->headerLen = fragHdrLen / 4;
  2128. d1477 11
  2129. d1500 5
  2130. a1504 1
  2131.         bcopy( (Address) dataPtr, 
  2132. d1506 1
  2133. d1519 3
  2134. a1521 1
  2135.     free(packet.base);
  2136. d1553 1
  2137. a1553 1
  2138.     (void) IP_Output(&queuedPacket);
  2139. d1556 1
  2140. a1556 1
  2141.     (void) IP_Output(packetPtr);
  2142. d1586 1
  2143. a1586 1
  2144.     (void) IP_Output(&queuedPacket);
  2145. @
  2146.  
  2147.  
  2148. 1.5
  2149. log
  2150. @Patches for SPUR
  2151. @
  2152. text
  2153. @d32 1
  2154. a32 1
  2155. static char rcsid[] = "$Header: ip.c,v 1.4 88/08/25 13:48:53 mendel Exp $ SPRITE (Berkeley)";
  2156. d295 1
  2157. d298 1
  2158. d937 1
  2159. a937 1
  2160.                     Net_HostToNetInt(ipHeaderPtr->dest);
  2161. d977 1
  2162. a977 1
  2163.                  Net_HostToNetInt(Rte_GetOfficialAddr(FALSE));
  2164. d1034 1
  2165. a1034 2
  2166.                 *addrPtr = 
  2167.                    Net_HostToNetInt(Rte_GetOfficialAddr(FALSE));
  2168. d1051 1
  2169. a1051 1
  2170.                 if (!Rte_AddrIsForUs(*addrPtr)) {
  2171. d1306 2
  2172. a1307 1
  2173.     
  2174. d1310 1
  2175. a1701 1
  2176. #include "io.h"
  2177. @
  2178.  
  2179.  
  2180. 1.4
  2181. log
  2182. @Patches for SPUR.
  2183. @
  2184. text
  2185. @d32 1
  2186. a32 1
  2187. static char rcsid[] = "$Header: ip.c,v 1.3 88/08/16 11:17:08 mendel Exp $ SPRITE (Berkeley)";
  2188. d689 1
  2189. a689 1
  2190.     ptr = packetPtr->base + sizeof(IPS_PacketNetHdr);
  2191. d1414 1
  2192. a1414 1
  2193.     packet.base = malloc((unsigned int) packet.totalLen);
  2194. d1416 1
  2195. a1416 1
  2196.     fragPtr = packet.base + sizeof(IPS_PacketNetHdr);
  2197. @
  2198.  
  2199.  
  2200. 1.3
  2201. log
  2202. @
  2203. @
  2204. text
  2205. @d32 1
  2206. a32 1
  2207. static char rcsid[] = "$Header: ip.c,v 1.2 88/04/27 09:08:43 brent Exp $ SPRITE (Berkeley)";
  2208. d1013 2
  2209. a1014 2
  2210.             addrPtr = Net_NetToHostInt((Net_InetAddress *)
  2211.                     (optionPtr + tsPtr->pointer -1));
  2212. d1668 2
  2213. a1669 1
  2214.     ipPtr->ident    = Net_HostToNetShort(ident)++;
  2215. @
  2216.  
  2217.  
  2218. 1.2
  2219. log
  2220. @New update with Jacobson enhancements
  2221. @
  2222. text
  2223. @d32 1
  2224. a32 1
  2225. static char rcsid[] = "$Header: ip.c,v 6.1 88/04/24 23:14:19 andrew Exp $ SPRITE (Berkeley)";
  2226. d45 1
  2227. a45 4
  2228. #include "sys.h"
  2229. #include "mem.h"
  2230. #include "time.h"
  2231. #include "byte.h"
  2232. d47 1
  2233. d130 1
  2234. d203 1
  2235. a203 1
  2236.     Sys_Panic(SYS_WARNING, "IP_SetProtocolHandler: bad protocol # (%d)\n",
  2237. d208 2
  2238. a209 2
  2239.     Sys_Panic(SYS_WARNING, 
  2240.         "IP_SetProtocolHandler: NULL procedure address\n");
  2241. d499 1
  2242. a499 1
  2243.     fragInfoPtr = Mem_New(DgramFragInfo);
  2244. d573 1
  2245. a573 1
  2246.             Mem_Free(packetPtr->base);
  2247. d607 2
  2248. a608 2
  2249.         Mem_Free((Address) dataPtr->fragPacket.base);
  2250.         Mem_Free((Address) dataPtr);
  2251. d632 1
  2252. a632 1
  2253.     newDataPtr = Mem_New(FragDataInfo);
  2254. d683 1
  2255. a683 1
  2256.      * We don't Mem_Free(packetPtr->base) before calling IPS_InitPacket 
  2257. d702 1
  2258. a702 2
  2259.         Byte_Copy(amtToCopy, (Address) dataPtr->fragPacket.ipPtr, 
  2260.                 (Address) ptr);
  2261. d712 2
  2262. a713 3
  2263.         Byte_Copy(dataPtr->dataLen, 
  2264.             (Address) dataPtr->fragPacket.ipPtr+dataPtr->dataOffset, 
  2265.             (Address) ptr);
  2266. d719 2
  2267. a720 2
  2268.     Mem_Free((Address) dataPtr->fragPacket.base);
  2269.     Mem_Free((Address) dataPtr);
  2270. d724 1
  2271. a724 1
  2272.     Mem_Free((Address) fragInfoPtr);
  2273. d766 2
  2274. a767 2
  2275.     Mem_Free((Address) ((FragDataInfo *)dataPtr)->fragPacket.base);
  2276.     Mem_Free((Address) dataPtr);
  2277. d770 1
  2278. a770 1
  2279.     Mem_Free((Address) fragInfoPtr);
  2280. d1065 3
  2281. a1067 2
  2282.             Byte_Copy(sizeof(time), (Address)&time, 
  2283.                     (Address) (optionPtr + tsPtr->pointer -1));
  2284. d1181 1
  2285. a1181 1
  2286.     Sys_Panic(SYS_WARNING, "SaveRoute (IP): optLen (%d) bad\n", optLen);
  2287. d1184 1
  2288. a1184 1
  2289.     Byte_Copy(optLen, optionPtr, (Address)&savedSrcRoute.route.info.type);
  2290. d1229 1
  2291. a1229 1
  2292.     routePtr = Mem_Alloc(len);
  2293. d1239 2
  2294. a1240 2
  2295.     Byte_Copy(sizeof(savedSrcRoute.route.info),
  2296.             (Address) &savedSrcRoute.route.info, routePtr);
  2297. d1414 1
  2298. a1414 1
  2299.     packet.base = Mem_Alloc(packet.totalLen);
  2300. d1440 2
  2301. a1441 2
  2302.         Byte_Copy(fragDataLen, (Address) dataPtr, 
  2303.             (Address) fragPtr+fragHdrLen);
  2304. d1454 1
  2305. a1454 1
  2306.     Mem_Free(packet.base);
  2307. d1487 1
  2308. a1487 1
  2309.     Mem_Free(queuedPacket.base);
  2310. d1490 1
  2311. a1490 1
  2312.     Mem_Free(packetPtr->base);
  2313. d1520 1
  2314. a1520 1
  2315.     Mem_Free(queuedPacket.base);
  2316. d1585 3
  2317. a1587 2
  2318.         Sys_Panic(SYS_WARNING, 
  2319.             "(IP) CopyOption: bad option length %d\n", optionLen);
  2320. d1595 1
  2321. a1595 1
  2322.         Byte_Copy(optionLen, (Address)srcPtr, (Address)destPtr);
  2323. d1714 1
  2324. a1714 1
  2325.     Io_Flush(io_StdOut);
  2326. d1719 2
  2327. a1720 2
  2328.     Io_Print("IP Packet: size = %d\n", packetPtr->ipLen);
  2329.     Io_Print("Protocol, version:    %s, %d\n", 
  2330. d1723 1
  2331. a1723 1
  2332.     Io_Print("Src, dest addrs:    %s, %s\n", srcAddr, destAddr);
  2333. d1725 1
  2334. a1725 1
  2335.     Io_Print("Header, total len:    %d, %d\n", 
  2336. d1727 1
  2337. a1727 1
  2338.     Io_Print("TOS, ttl:        %x, %d\n", 
  2339. d1731 1
  2340. a1731 1
  2341.     Io_Print("checksum, recomp:    %x, %x\n", checksum, 
  2342. d1734 1
  2343. a1734 1
  2344.     Io_Print("Frag flags, offset, ID:    %x, %d, %x\n", 
  2345. d1737 1
  2346. a1737 1
  2347.     Io_Print("\n");
  2348. d1739 1
  2349. a1739 1
  2350.     Io_Flush(io_StdOut);
  2351. d1741 1
  2352. a1741 1
  2353.     Mem_Free(packetPtr->base);
  2354. d1749 1
  2355. a1749 1
  2356.     char buffer[5];
  2357. d1763 1
  2358. a1763 1
  2359.         Io_PrintString(buffer, "%4d", num);
  2360. @
  2361.  
  2362.  
  2363. 1.1
  2364. log
  2365. @Initial revision
  2366. @
  2367. text
  2368. @d17 2
  2369. a18 2
  2370.  *    "@@(#)ip_input.c  7.5 (Berkeley) 6/4/87"
  2371.  *    "@@(#)ip_output.c 7.5 (Berkeley) 5/24/87"
  2372. d32 1
  2373. a32 1
  2374. static char rcsid[] = "$Header: ip.c,v 6.0 87/09/08 15:55:37 andrew Stable $ SPRITE (Berkeley)";
  2375. a262 1
  2376.     register DgramFragInfo    *fragInfoPtr;
  2377. a263 1
  2378.     Boolean            foundFrags;
  2379. d334 5
  2380. a338 5
  2381.      * This packet may be a complete datagram or a fragment of one.
  2382.      * In either case we must check to see if there are any existing fragments 
  2383.      * for this datagram. If the packet is complete and there are fragments,
  2384.      * they can be freed since they are no longer needed. If the packet 
  2385.      * is a fragment, then see if it will help form a complete datagram.
  2386. d340 2
  2387. a341 1
  2388.     
  2389. d343 2
  2390. a344 10
  2391.     foundFrags = FALSE;
  2392.     LIST_FORALL(&fragInfoList, (List_Links *) fragInfoPtr) {
  2393.     if ((ipHeaderPtr->ident == fragInfoPtr->ident) &&
  2394.         (ipHeaderPtr->protocol == fragInfoPtr->protocol) &&
  2395.         (ipHeaderPtr->source == fragInfoPtr->source) &&
  2396.         (ipHeaderPtr->dest == fragInfoPtr->dest)) {
  2397.         foundFrags = TRUE;
  2398.         break;
  2399.     }
  2400.     }
  2401. d346 1
  2402. a346 2
  2403.     if (( !(ipHeaderPtr->flags & NET_IP_MORE_FRAGS)) &&
  2404.     (ipHeaderPtr->fragOffset == 0)) {
  2405. d348 9
  2406. a356 6
  2407.     /*
  2408.      * This packet is complete. Free the fragments if they exist.
  2409.      */
  2410.  
  2411.     if (foundFrags) {
  2412.         (void) FreeFragments(fragInfoPtr);
  2413. a357 7
  2414.     } else {
  2415.     /*
  2416.      * This packet is a fragment.
  2417.      */
  2418.  
  2419.     stats.ip.fragsRcv++;
  2420.  
  2421. d361 1
  2422. @
  2423.